#include "D3DManager.h"

/*
	File:	D3DManager.cpp
	Author:	TJ Ashby
	
	Comments:	Sets up Direct X for our game.
*/

D3DManager::D3DManager()
{

}


D3DManager::~D3DManager(void)
{

}

D3DManager* D3DManager::getInstance()
{
	static D3DManager instance;

	return &instance;
}

void D3DManager::Initialize(HINSTANCE hInst,HWND hWnd,String Title,WNDPROC WndProc,unsigned WindowWidth,unsigned WindowHeight,bool Fullscreen,int ShowCmd)
{
#ifdef _DEBUG
	cout << "Creating Window...";
#endif
	WNDCLASSEX	wc;

	wndWidth = WindowWidth;
	wndHeight = WindowHeight;

	ZeroMemory(&wc,sizeof(wc));
	wc.cbSize         = sizeof( WNDCLASSEX );             // size of window structure
	wc.lpfnWndProc    = this->wndProc = WndProc;						// message callback
	wc.lpszClassName  = L"DirectX";             // class name
	wc.hInstance      = hInstance = hInst;		                // handle to application
	wc.hCursor        = LoadCursor( nullptr, IDC_ARROW );    // default cursor
	wc.hbrBackground  = ( HBRUSH )( COLOR_WINDOWFRAME );  // background brush

	RegisterClassEx(&wc);

	int x = 0;
	int y = 0;

	if(!Fullscreen)
		x = y = CW_USEDEFAULT;

	this->hwnd = CreateWindowA("DirectX",Title,Fullscreen ? WS_EX_TOPMOST | WS_POPUP : WS_OVERLAPPEDWINDOW,						// window style
		x, y,               // x & y coordinates
		WindowWidth, WindowHeight,                // width & height of window
		nullptr, nullptr,                                 // parent window & menu
		hInstance,				                // handle to application
		nullptr );

	ShowWindow(hwnd,ShowCmd);
	UpdateWindow(hwnd);

	ZeroMemory(&msg,sizeof(MSG));

	d3dDevice = nullptr;
	d3dObject = nullptr;

#ifdef _DEBUG
	cout << " Complete\n";
#endif

	/* Initiate DirectX for our windowed program */
#ifdef _DEBUG
	cout << "Initializing DirectX...";
#endif
	ZeroMemory(&d3dpp,sizeof(D3DPRESENT_PARAMETERS));
	d3dpp.hDeviceWindow					= hwnd;
	d3dpp.Windowed						= !Fullscreen;
	d3dpp.BackBufferWidth				= WindowWidth;
	d3dpp.BackBufferHeight				= WindowHeight;
	d3dpp.PresentationInterval			= D3DPRESENT_INTERVAL_IMMEDIATE;
	d3dpp.SwapEffect					= D3DSWAPEFFECT_DISCARD;
	d3dpp.AutoDepthStencilFormat		= D3DFMT_D16;
	d3dpp.EnableAutoDepthStencil		= true;

	// Get access to the video card
	d3dObject = Direct3DCreate9(D3D_SDK_VERSION);
	d3dObject->CreateDevice(0,D3DDEVTYPE_HAL,hwnd,D3DCREATE_HARDWARE_VERTEXPROCESSING,&d3dpp,&d3dDevice);

	// Get Direct X ready to draw a line at any moment
	D3DXCreateLine(D3DManager::getInstance()->d3dDevice,&d3dLine);

#ifdef _DEBUG
	cout << " Complete\n";
#endif
}

void D3DManager::Shutdown()
{
#ifdef _DEBUG
	cout << "Shutting Down DirectX...";
#endif
	if(d3dDevice)
		d3dDevice->Release();
	if(d3dObject)
		d3dObject->Release();

	d3dDevice = nullptr;
	d3dObject = nullptr;

#ifdef _DEBUG
	cout << " Complete\n";
#endif
}

bool D3DManager::Running()
{
	if(PeekMessage(&msg,hwnd,0,0,PM_REMOVE))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);

		if(msg.message == WM_QUIT)
			return false;
	}


	return true;
}

void D3DManager::Begin()
{
	d3dDevice->BeginScene();
}

void D3DManager::End()
{
	d3dDevice->EndScene();
}

void D3DManager::Clear( Color &color )
{
	d3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, color, 1, 0);
}

void D3DManager::DrawRectangle( float left,float top,float right,float bottom,Color &BorderColor,Color &FillColor,float BorderWidth )
{
	d3dLine->Begin();

	for(int i = 0;i < (bottom-top-BorderWidth);++i)
	{
		Vector2 fill[] = { Vector2(float(left+BorderWidth),float(top+i+BorderWidth)),Vector2(float(right-BorderWidth+1),float(top+i+BorderWidth)) };
		d3dLine->Draw(fill,2,FillColor);
	}
	for(int i = 0;i < BorderWidth;++i)
	{
		for(unsigned j = 0;j < 4;++j)
		{
			Vector2 border1[] = { Vector2(float(left) ,float(top+i)), D3DXVECTOR2(float(right),float(top+i)) };
			Vector2 border2[] = { Vector2(float(left) ,float(bottom-i)), D3DXVECTOR2(float(right),float(bottom-i)) };

			d3dLine->Draw(border1,2,BorderColor);
			d3dLine->Draw(border2,2,BorderColor);
		}
		for(unsigned j = 0;j < 4;++j)
		{
			Vector2 border1[] = { Vector2(float(left+i) ,float(top)), D3DXVECTOR2(float(left+i),float(bottom)) };
			Vector2 border2[] = { Vector2(float(right-i) ,float(top)), D3DXVECTOR2(float(right-i),float(bottom)) };

			d3dLine->Draw(border1,2,BorderColor);
			d3dLine->Draw(border2,2,BorderColor);
		}
	}


	d3dLine->End();
}

void D3DManager::DrawRectangle( const RECT &rect,Color &BorderColor,Color &FillColor,float BorderWidth )
{
	d3dLine->Begin();

	for(int i = 0;i < (rect.bottom-rect.top-1);++i)
	{
		Vector2 fill[] = { Vector2(float(rect.left+BorderWidth),float(rect.top+i+BorderWidth)),Vector2(float(rect.right-BorderWidth+1),float(rect.top+i+BorderWidth)) };
		d3dLine->Draw(fill,2,FillColor);
	}
	for(int i = 0;i < BorderWidth;++i)
	{
		for(unsigned j = 0;j < 4;++j)
		{
			Vector2 border1[] = { Vector2(float(rect.left) ,float(rect.top+i)), D3DXVECTOR2(float(rect.right),float(rect.top+i)) };
			Vector2 border2[] = { Vector2(float(rect.left) ,float(rect.bottom-i)), D3DXVECTOR2(float(rect.right),float(rect.bottom-i)) };

			d3dLine->Draw(border1,2,BorderColor);
			d3dLine->Draw(border2,2,BorderColor);
		}
		for(unsigned j = 0;j < 4;++j)
		{
			Vector2 border1[] = { Vector2(float(rect.left+i) ,float(rect.top)), D3DXVECTOR2(float(rect.left+i),float(rect.bottom)) };
			Vector2 border2[] = { Vector2(float(rect.right-i) ,float(rect.top)), D3DXVECTOR2(float(rect.right-i),float(rect.bottom)) };

			d3dLine->Draw(border1,2,BorderColor);
			d3dLine->Draw(border2,2,BorderColor);
		}
	}


	d3dLine->End();
}

void D3DManager::DrawTriangle( Vector2 &Point1,Vector2 &Point2,Vector2 &Point3,Color &BorderColor,Color &FillColor,float BorderWidth )
{
	//
}

void D3DManager::DrawTriangle( Vector2 Points[3],Color &BorderColor,Color &FillColor,float BorderWidth )
{
	//
}

void D3DManager::DrawCircle( const Vector2 &Center,float Radius,unsigned short Sides,Color &color )
{
	float Angle = D3DXToRadian(360.0f/Sides);

	float Cos = cos(Angle);
	float Sin = sin(Angle);

	Vector2 vec(Radius,0);

	for(unsigned short i = 0;i < Sides;++i)
	{
		Vector2 rot( Cos*vec.x - Sin*vec.y , Sin*vec.x + Cos*vec.y );
		rot += Center;
		vec += Center;
		DrawLine(vec,rot,color);
		vec = rot - Center;
	}
}

void D3DManager::DrawCircle( const Vector2 &Center,float Radius1,float Radius2,unsigned short Sides,Color &color )
{
	//
}

void D3DManager::DrawLine( const Vector2 &Point1,const Vector2 &Point2,Color color )
{
	d3dLine->Begin();

	Vector2 Points[2] = { Point1,Point2 };
	d3dLine->Draw(Points,2,color);

	d3dLine->End();
}

void D3DManager::DrawLine( const Vector2 *Points,unsigned PointCount,Color color )
{
	d3dLine->Begin();
	d3dLine->Draw(Points,PointCount,color);
	d3dLine->End();
}

void D3DManager::Present()
{
	d3dDevice->Present(0,0,0,0);
}

